Import yimWork

'summary: Main class for sprites. Handles movement, collision, scaling, everythang!
Class yimSprite
	Field img:Image
	Field isAnimated:Bool=False
	Field numFrames:Int
	Field scale:yimVec2D = New yimVec2D(1.0, 1.0)
	Field pos:yimVec2D = New yimVec2D(0, 0)
	Field drawRect:yimRect
	
	Field ang:Float=0.0
	Field angularRotation:Float=0.0
	Field vel:yimVec2D = New yimVec2D(0, 0)
	Field visible:Bool=True
	Field curFrame:Int=0
	Field moveRelative:Bool=False
	
	Field camPos:yimVec2D
	Field camSpeed:yimVec2D = New yimVec2D(1.0, 1.0)
	Field vScale:yimVec2D
	Field drawPos:yimVec2D = New yimVec2D(0, 0)
	Field repeatX:Bool=False
	Field repeatY:Bool=False
	
	Field dbgDrawCommands:Int = 0
	
	Field timeOfDeath:Int = 0
	
	Field collGroup:yimCollGroup = Null
	Field collBody:yimCollBody = Null
	
	Field physBody:yimBox2DBody = Null
	
	Field followSpr:yimSprite
	Field followAngOffset:Float
	
	Field followedBy:List<yimSprite> = New List<yimSprite>()
	
	Field pathConn:yimSpritePathConnector = Null	

	Field colorSprite:Bool = False
	Field color:yimColor = New yimColor(0, 0, 0)
	Field alpha:Float = 1.0
	
	Field gravity:Float = 0.0
	Field maxVel:yimVec2D = New yimVec2D(1000, 1000)
	Field minVel:yimVec2D = New yimVec2D(-1000, -1000)
	Field friction:yimVec2D = New yimVec2D(1.0, 1.0)
	
	Field updateCallBack:yimSpriteUpdateCallBack = Null
	
	Field parent:yimSpriteLayer = Null
	
	Field minPos:yimVec2D = New yimVec2D(-65535, -65535)
	Field maxPos:yimVec2D = New yimVec2D(65535, 65535)
	
	Field spritesAttached:List<yimSpriteLink> = New List<yimSpriteLink>()
	Field attachedTo:yimSprite = Null
	
	Field anims:List<yimSpriteAnimation> = New List<yimSpriteAnimation>()
	Field curAnim:yimSpriteAnimation = Null
	Field animStartTime:Float = 0
	Field animPlayCount:Int = 0
	Field id:String = ""
	
	Field delayedDel:Bool = False
	
	Field pointInDir:Bool = False
	Field pointInDirOffset:Float = 0.0
	
	Field draggable:Bool = False
	Field dragCenter:Bool = True
	
	Field juicies:List<yimJuicyBase> = New List<yimJuicyBase>()
	
	Method New(_parent:yimSpriteLayer, file:String, frameWidth:Int=-1, frameHeight:Int=-1, _numFrames:Int=1, flags:Int=Image.MidHandle)
		parent = _parent
		
		If file <> ""
			img = parent.parent.eng.images.Get(file)
			If Not img
				If frameWidth > 0 And frameHeight > 0
					img = LoadImage(file, frameWidth, frameHeight, _numFrames, flags)
				Else
					img = LoadImage(file, 1, flags)
				EndIf
'				parent.parent.eng.images.Add(file, img)
			Endif
			
		EndIf
		
		numFrames = _numFrames
	End
	
	'summary: Gets da width
	Method Width:Float()
		Return (img.Width()*Abs(scale.x) * vScale.x)
	End
	
	'summary: Gets da height
	Method Height:Float()
		Return (img.Height()*Abs(scale.y) * vScale.y)
	End
	
	'summary: Adds a "juicy" action to the juicy queue for this sprite
	Method AddJuicy(juicy:yimJuicyBase)
		juicies.AddLast(juicy)
		juicy.spr = Self
	End
	
	'summary: Attaches a sprite to this sprite. Provide the offset position and whether or not you want the attached sprite to rotate with the sprite
	Method AttachSprite:yimSpriteLink(spr:yimSprite, offX:Float=0, offY:Float=0, lockRotation:Bool=False, doFrameOffsets:Bool=False)
		Local tLink:= New yimSpriteLink(Self, spr, offX, offY, lockRotation, doFrameOffsets)
		spr.attachedTo = Self
		
		spritesAttached.AddLast(tLink)
		
		Return tLink
	End
	
	'summary: Detaches the passed sprite from this sprite, if attached, of course.
	Method DetachSprite(spr:yimSprite)
		For Local tLink:= EachIn spritesAttached
			If tLink.spr = spr
				spritesAttached.Remove(tLink)
				spr.attachedTo = Null
			EndIf
		Next
	End
	
	'summary: Add an animation which can later be called by name.
	Method AddAnimation:yimSpriteAnimation(name:String, startFrame:Int, endFrame:Int, framesPerSec:Int)
		Local tAnim:= New yimSpriteAnimation(name, startFrame, endFrame, framesPerSec)
		anims.AddLast(tAnim)
		Return tAnim
	End
	
	'summary: Sets an event to be called when a particular frame of the sprite is drawn. Perfect for syncing footstep noises.
	Method SetFrameEvent(animName:String, frame:Int, callback:yimFrameEvent)
		Local tAnim:= GetAnimation(animName)
		If tAnim
			tAnim.SetFrameEvent(frame, callback)
		EndIf
	End
	
	'summary: Gets a yimSpriteAnimation object by name
	Method GetAnimation:yimSpriteAnimation(name:String)
		For Local a:= EachIn anims
			If a.name = name
				Return a
			EndIf
		Next
		
		Return Null
	End
	
	'summary: Play an animation using the name of it. Can also pass the number of times to play this animation. 0 is looping.	
	Method PlayAnimation(animName:String, playCount:Int=0)
		PlayAnimation(GetAnimation(animName), playCount)
	End
	
	'summary: Play an animation by its yimSpriteAnimation object reference. Can also pass the number of times to play this animation. 0 is looping.	
	Method PlayAnimation(anim:yimSpriteAnimation, playCount:Int=0)
		If anim <> curAnim
			curAnim = anim
			animStartTime = Millisecs()
			animPlayCount = playCount
		EndIf
	End
	
	'summary: Stop that animation!
	Method StopAnimation()
		curAnim = Null
	End
	
	'summary: Sets the sprite as a draggable object for mouse/touch operations.
	Method SetDraggable(dragToggle:Bool=True, dragCent:Bool=True)
		draggable = dragToggle
		dragCenter = dragCent
	End
	
	'summary: Sets the alpha value of the sprite from 0.0 (invisible) to 1.0 (opaque)
	Method SetSpriteAlpha(_alpha:Float=1.0)
		alpha = _alpha
	End
	
	'summary: Sets the color (tint) of the sprite with your standard r, g, b values (0 - 255)
	Method SetSpriteColor(red:Float, green:Float, blue:Float)
		color.r = red
		color.g = green
		color.b = blue
		
		colorSprite = True
	End
	
	'summary: Clears any sprite tinting.
	Method ClearSpriteColor()
		colorSprite = False	
	End
	
	'summary: Sets the position of the sprite in map space. Not on screen. So (0, 0) is the middle of the screen.
	Method SetPosition(pX:Float, pY:Float)
		pos.x = pX
		pos.y = pY
	End
	
	'summary: Sets the movement speed of the sprite based on its current angle
	Method SetSpeed(spd:Float)
		SetSpeedXY(Sin(ang-180.0)*spd, Cos(ang-180.0)*spd)

	End
	
	'summary: Sets the movement speed of the sprite in the x and y directions
	Method SetSpeedXY(x:Float, y:Float)
		vel.x = x
		vel.y = y
	End
	
	'summary: Sets the movement speed of the sprite in the x (left and right) direction
	Method SetSpeedX(x:Float)
		vel.x = x
	End
	
	'summary: Sets the movement speed of the sprite in the y (up and down) direction
	Method SetSpeedY(y:Float)
		vel.y = y
	End
	
	'summary: Increases velocity of the sprite in the x and y directions
	Method IncVel(x:Float, y:Float)
		vel.x += x
		vel.y += y
	End
	
	'summary: Increases the velocity of the sprite in the x (left and right) direction
	Method IncVelX(x:Float)
		vel.x += x
	End
	
	'summary: Increases the velocity of the sprite in the y (up and down) direction
	Method IncVelY(y:Float)
		vel.y += y
	End
	
	'summary: Sets the maximum velocity of the sprite in the x and y directions
	Method SetMaxVel(x:Float, y:Float)
		maxVel.Set(x, y)
	End
	
	'summary: Sets the minimum velocity of the sprite in the x and y directions
	Method SetMinVel(x:Float, y:Float)
		minVel.Set(x, y)
	End
	
	'summary: Sets the minimum velocity of the sprite in the y direction
	Method SetMinY(y:Float)
		minPos.y = y
	End
	
	'summary: Sets the maximum velocity of the sprite in the y direction
	Method SetMaxY(y:Float)
		maxPos.y = y
	End
	
	'summary: Sets the minimum velocity of the sprite in the x direction
	Method SetMinX(x:Float)
		minPos.x = x
	End

	'summary: Sets the maximum velocity of the sprite in the x direction
	Method SetMaxX(x:Float)
		maxPos.x = x
	End
	
	'summary: Sets the rate at which the sprite automatically slows. The closer to 1, the longer it takes to slow down.
	Method SetLinearDampening(x:Float, y:Float)
		friction.Set(x, y)
	End
	
	'summary: Sets the speed of the camera in the x and y directions
	Method SetCameraSpeed(x:Float, y:Float)
		camSpeed.Set(x, y)
	End
	
	'summary: Sets the callback to call... back every time the sprite is update. This is for added user control of the update call without having to modify yimSprite.
	Method SetUpdateCallBack(cb:yimSpriteUpdateCallBack)
		updateCallBack = cb
	End
	
	'summary: Sets the time, in milliseconds, at which the sprite should be deleted from the game. Ex: SetTimeOfDeath(Millisecs() + 4000) will kill the sprite in 4 seconds.
	Method SetTimeOfDeath(mills:Float)
		timeOfDeath = mills
	End
	
	'summary: Sets a sprite to follow, angularly. So it will just point to the sprite at all times. You can provide an offset if it doesn't point at quite the right angle.
	Method SetToFollow(spr:yimSprite, followAngleOffset:Float=0.0)
		followSpr = spr
		followAngOffset = followAngleOffset
		spr.followedBy.AddLast(Self)
	End
	
	'summary: Stops following a sprite, if following a sprite.
	Method CancelFollow()
		If followSpr
			followSpr.followedBy.Remove(Self)
			followSpr = Null
		EndIf
	End
	
	'summary: Sets the sprite to move relative to itself and its angle. So if the sprite is angled 45 degrees, instead of moving horizontally 5 map moints when MoveX(5) is called, it'll move 5 points in the 45 degree direction.
	Method SetMoveRelative(moveRel:Bool=True)
		moveRelative = moveRel
	End
	
	'summary: Locks the sprites vertical movement (Sets camSpeed.y to 0.0) so no matter how much the camera moves up and down, the sprite will render in the same y position on the screen. Good for backgrounds.
	Method LockVertical()
		camSpeed.y = 0.0
	End
	
	'summary: Locks the sprites horizontal movement (Sets camSpeed.x to 0.0) so no matter how much the camera moves left and right, the sprite will render in the same x position on the screen. Good for backgrounds.
	Method LockHorizontal()
		camSpeed.x = 0.0
	End
	
	'summary: Repeats the sprite in the x direction infinitely. Good for side-scrolling backgrounds.
	Method SetRepeatX(doRepeat:Bool=True)
		repeatX = doRepeat
	End
	
	'summary: Repeats the sprite in the y direction infinitely. Good for scrolling backgrounds.
	Method SetRepeatY(doRepeat:Bool=True)
		repeatY = doRepeat
	End
	
	'summary: Sets gravity value of the current sprite. All sprites are 0 by default, so they need to be set individually to get gravity working in your game.
	Method SetGravity(grav:Float)
		gravity = grav
	End
	
	'summary: Flips the sprite in the x direction
	Method FlipX()
		scale.x = scale.x*-1
	End
	
	'summary: Flips the sprite in the y direction
	Method FlipY()
		scale.y = scale.y*-1
	End
	
	'summary: Point the sprite at a particular map point. Can provide an offset angle for proper pointing
	Method PointAt(x:Float, y:Float, offsetAngle:Float=0.0)
		SetAngle(ATan2(pos.x-x, pos.y-y) + offsetAngle)
	End
	
	'summary: Move the sprite in the x and y directions. A boolean can be passed in for relative movement on the fly.
	Method MoveXY(x:Float, y:Float, relative:Bool=False)
		If Not relative
			pos.x += x*vScale.x
			pos.y += y*vScale.y
		Else
			Local relx:Float = Sin(ang+90)*x + Sin(ang-180.0)*y
			Local rely:Float = Cos(ang+90)*x + Cos(ang-180.0)*y
			
			'Debug("rel x: "+relx)
			'Debug("rel y: "+rely)
			pos.x += yimDelta(relx)
			pos.y += yimDelta(rely)
		EndIf
		
		If pos.y < minPos.y
			pos.y = minPos.y
			vel.y = 0
		EndIf
		
		If pos.y > maxPos.y
			pos.y = maxPos.y
			vel.y = 0
		EndIf
		
		If pos.x < minPos.x
			pos.x = minPos.x
			vel.x = 0
		EndIf
		
		If pos.x > maxPos.x
			pos.x = maxPos.x
			vel.x = 0
		EndIf
	End
	
	'summary: Sets the angle of the sprite, in degrees. Not radians.
	Method SetAngle(angle:Float)
		ang = angle
	End
	
	'summary: Sets the rotation of the sprite. Set this to a value and watch it turn!
	Method SetRotation(amount:Float)
		angularRotation = amount
	End
	
	'summary: Rotates the sprite by the provided amount (in degrees), just once per call.
	Method RotateByAmount(amount:Float)
		SetAngle(ang+yimDelta(amount))
	End
	
	'summary: Moves the sprite by the provided amount according to its angle
	Method Move(amount:Float)
		Local transX:Float = Cos(ang)*amount
		Local transY:Float = Sin(ang-180.0)*amount
		
		MoveXY(transX, transY)
	End
	
	'summary: Tells yimEngine that this sprite is animated, and to treat it as such.
	Method SetAnimated(animated:Bool)
		isAnimated = animated
	End
	
	'summary: Determines whether or not to render/update the sprite.
	Method SetVisible(isVisible:Bool)
		visible = isVisible
	End
	
	'summary: Sets the sprite to a certain frame of its animation.
	Method SetFrame(frame:Int)
		curFrame = frame
	End
	
	Method SetVirts(sca:yimVec2D)
		vScale = sca
	End
	
	'summary: Connects the sprite to the provided yimPath. Once connected, it will automatically start moving on the path.
	Method ConnectToPath(path:yimPath, initialSpeed:Float=0.0, initialDir:Int=1, initialPos:Float=0.0)
		If pathConn
			pathConn = Null
		EndIf
		
		pathConn = New yimSpritePathConnector(Self, path, initialSpeed, initialDir, initialPos)
		
	End

	Method Update()
		If physBody
			SetPosition(physBody.GetPosition().x * parent.parent.b2dWorld.physScale, physBody.GetPosition().y * parent.parent.b2dWorld.physScale)
			SetAngle(ToDegrees(physBody.GetAngle()))
		Else

			If pathConn
				pathConn.Advance()
			EndIf
		
			If followSpr
				PointAt(followSpr.pos.x, followSpr.pos.y, followAngOffset)
			EndIf
			
			
			vel.y += gravity
			
			vel.x = vel.x * friction.x
			
			vel.y *= friction.y
			
			If juicies.Count() > 0
				For Local tj:= EachIn juicies
					If tj.Update()
						
					Else
						juicies.Remove(tj)
					EndIf
				Next
			Else
				MoveXY(vel.x, vel.y, moveRelative)
			EndIf
			
			
			
			If pointInDir
				SetAngle(ATan2(vel.x, vel.y) + pointInDirOffset)
			Else
				RotateByAmount(angularRotation)
			EndIf
			
			If collGroup And collBody
				collBody.Update(pos.x, pos.y)
				For Local curGrp:yimCollGroupLink = EachIn collGroup.collidesWith
					For Local curBody:yimCollBody = EachIn curGrp.collGroup.bodyList
						If collBody.IsColliding(curBody)
							'collBody.collingList.AddLast(curBody)
							If curGrp.callback
								curGrp.callback.Call(collBody, curBody)
								
								If Not collBody
									Exit
								EndIf
							EndIf
						EndIf
					Next
					
					If Not collBody
						Exit
					EndIf
				Next
			EndIf
		
		EndIf
		
		If updateCallBack
			updateCallBack.Call(Self)
		EndIf
		

		
		If spritesAttached
			Local xMod:Float = scale.x/Abs(scale.x)
			Local yMod:Float = scale.y/Abs(scale.y)
			
			For Local aSpr:= EachIn spritesAttached
				aSpr.spr.scale.x = scale.x
				If aSpr.lockRot
					aSpr.spr.SetAngle(ang)
					
				EndIf
				
				If aSpr.frameOffsets
					If aSpr.frameOffsets[curFrame]
						Local offX:Float = pos.x+aSpr.frameOffsets[curFrame].x*xMod
						Local offY:Float = pos.y+aSpr.frameOffsets[curFrame].y*yMod
						
						If aSpr.lockRot
							Local xDiff:Float = offX - pos.x
							Local yDiff:Float = offY - pos.y
							'If aSpr.frameOffsets[curFrame].x < 0 Then dist *= -1.0
							Local xPos:Float = pos.x+Sin(ang+90)*xDiff
							xPos += Sin(ang)*yDiff
							
							Local yPos:Float = pos.y+Cos(ang+90)*xDiff
							yPos += Cos(ang)*yDiff
							
							aSpr.spr.SetPosition(xPos, yPos)
						Else
							aSpr.spr.SetPosition(offX, offY)
						EndIf
						'arms.pos.x+Sin(shootAng)*80.0, arms.pos.y-10+Cos(shootAng)*80.0)
					EndIf
				Else
					aSpr.spr.SetPosition(pos.x+aSpr.offset.x*xMod, pos.y+aSpr.offset.y*yMod)
				EndIf

			Next
		EndIf


		drawRect.SetPosition(pos.x*vScale.x, -pos.y*vScale.y)
		drawRect.SetScale(scale.x * vScale.x, scale.y * vScale.y)
		drawRect.SetAngle(ang)
		drawRect.Update()
	End
	
	Method Render()
		
		Local eng:yimEngine = parent.parent.eng
		
		Local onScreen:Bool = RectInRect(drawRect, eng.screenRect)

		yim_SaveAlpha()
		SetAlpha(alpha)
		
		If onScreen
		
			PushMatrix()
			
			Translate(pos.x*camSpeed.x, -pos.y*camSpeed.y)
			Scale(scale.x, scale.y)
			Rotate(ang)
			
			If curAnim
				curFrame = curAnim.GetFrame(animStartTime, Millisecs(), animPlayCount)
			EndIf
			
			If colorSprite
				yim_SaveColor()
				SetColor(color.r, color.g, color.b)
				DrawImage(img, 0, 0, curFrame)
				yim_RestoreColor()
			Else
				DrawImage(img, 0, 0, curFrame)
			EndIf
			
			
			
			If yim_debugMode
				If physBody
					Debug("Phys body: "+physBody.GetPosition().x+" "+physBody.GetPosition().y)
				EndIf
				If collBody And eng.dbgDrawCollBodies

					collBody.Draw(0, 0)

				EndIf
								
			EndIf
			
			PopMatrix()
			eng.dbgDrawCommands += 1
		EndIf
			

		yim_RestoreAlpha()
		
	End
	
	Method DrawRepeatX(start:Float, y:Float, hW:Float)
		While start < DeviceWidth()+hW
			DrawImage(img, start, y, ang, scale.x * vScale.x, scale.y * vScale.y, curFrame)
			parent.parent.eng.dbgDrawCommands += 1
			start += hW*2.0
		Wend	
	End
	
	Method DrawRepeatY(start:Float, x:Float, hH:Float)
		While start < DeviceHeight()+hH
			DrawImage(img, x, start, ang, scale.x * vScale.x, scale.y * vScale.y, curFrame)
			start += hH*2.0
			parent.parent.eng.dbgDrawCommands += 1
		Wend
	End
End

Class yimSpriteAnimation
	Field startFrame:Int
	Field curFrame:Int
	Field numFrames:Int
	Field endFrame:Int
	Field name:String
	Field fps:Int
	Field frameEvents:yimFrameEvent[]
	
	Method New(_name:String, _startFrame:Int, _endFrame:Int, _fps:Int)
		name = _name
		startFrame = _startFrame
		curFrame = startFrame
		endFrame = _endFrame
		numFrames = endFrame-startFrame
		fps = _fps
		frameEvents = New yimFrameEvent[numFrames]
	
		For Local i:= 0 Until frameEvents.Length
			frameEvents[i] = Null	
		Next
	End
	
	Method GetFrame:Int(startTime:Float, curTime:Float, playCount:Int=0)
		Local frame:= startFrame + ((curTime-startTime)/(1000.0/fps)) Mod numFrames
		If playCount > 0
			If (curTime-startTime) >= ((1000.0/fps)*numFrames)*playCount
				Return endFrame-1
			EndIf
		EndIf
		Return frame 
	End
	
	Method SetFrameEvent(frame:Int, callback:yimFrameEvent)
		frameEvents[frame] = callback
	End
	
	Method CheckFrameEvent(frame:Int)
		If frameEvents[frame]
			frameEvents[frame].Call()
		EndIf
	End
End

Class yimFrameEvent
	Method Call()
		
	End
End

Class yimSpriteLink
	Field spr:yimSprite
	Field srcSpr:yimSprite
	
	Field offset:yimVec2D
	Field angOff:Float = 0.0
	Field frameOffsets:yimVec2D[]
	Field lockRot:Bool = False
	
	Method New(_srcspr:yimSprite, _spr:yimSprite, offsetX:Float=0, offsetY:Float=0, lockRotation:Bool=False, doFrameOffsets:Bool=False)
		spr = _spr
		offset = New yimVec2D(offsetX, offsetY)
		srcSpr = _srcspr
		
		lockRot = lockRotation
		If doFrameOffsets
			frameOffsets = New yimVec2D[srcSpr.numFrames]
		EndIf
	End
	
	Method SetAngOffset(ang:Float)
		angOff = ang
	End
	
	Method SetFrameOffset(frame:Int, xPos:Float, yPos:Float)
		If frameOffsets
			frameOffsets[frame] = New yimVec2D(xPos, yPos)
		EndIf
	End
End

Class yimSpriteUpdateCallBack
	Method Call(this:yimSprite)
		
	End
End

Class yimSpriteLayer
	Field sprList:List<yimSprite> = New List<yimSprite>()
	Field delSprList:List<yimSprite> = New List<yimSprite>()
	
	Field tileMapList:List<yimTileMap> = New List<yimTileMap>()
	
	Field visible:Bool=True
	Field name:String
	
	Field parent:yimSpriteWorld
	
	Method New(_parent:yimSpriteWorld, _name:String)
		name = _name
		parent = _parent
	End
	
	Method AddTileMap:yimTileMap(tileWidth:Float, tileHeight:Float, numTilesX:Int, numTilesY:Int, xPos:Float=0.0, yPos:Float=0.0)
		Local tMap:yimTileMap = New yimTileMap(Self, tileWidth, tileHeight, numTilesX, numTilesY, xPos, yPos)
		tileMapList.AddLast(tMap)
		Return tMap
	End
	
	Method AddSprite(spr:yimSprite)
		sprList.AddLast(spr)
		spr.parent = Self
	End
	
	Method RemoveSprite(spr:yimSprite)
		delSprList.AddLast(spr)
		If spr.collBody
			spr.collGroup.RemoveBody(spr.collBody)
			spr.collBody = Null
		EndIf
		
		If spr.attachedTo
			spr.attachedTo.DetachSprite(spr)
		EndIf
		
		spr.CancelFollow()
		
		For Local tFol:= EachIn spr.followedBy
			tFol.followSpr = Null
		Next
		
		
	End
	
	Method Update()
		Local mills:Float = Millisecs()
		
		For Local tSpr:= EachIn sprList
			If tSpr.visible
				tSpr.Update()
			Endif
			
			If tSpr.timeOfDeath > 0
				If mills >= tSpr.timeOfDeath
					tSpr.visible = False
					parent.eng.DelayedRemoveSprite(tSpr)
					sprList.Remove(tSpr)
				EndIf
			EndIf
		Next
		
		
	End
	
	Method Reset()
		For Local tSpr:= EachIn sprList
			RemoveSprite(tSpr)	
		Next
		
		For Local tSpr:= EachIn delSprList
			sprList.Remove(tSpr)
		Next
		delSprList.Clear()
		
		tileMapList.Clear()
	End
	
	Method Render()
		If delSprList.Count() > 0
			For Local tSpr:= EachIn delSprList
				sprList.Remove(tSpr)
			Next
			delSprList.Clear()
		EndIf
		
		For Local tSpr:= EachIn sprList
			If tSpr.visible
				tSpr.Render()
			Endif
		Next
		
		For Local tMap:= EachIn tileMapList
			If tMap.doDrawGrid
				tMap.DrawGrid()			
			EndIf
		Next
	End
End

Class yimSpriteWorld
	Field layerList:List<yimSpriteLayer> = New List<yimSpriteLayer>()
	Field curLayer:yimSpriteLayer

	Field vScale:yimVec2D = New yimVec2D(1.0, 1.0)
	Field eng:yimEngine
		
	Field b2dWorld:yimBox2DWorld
	Field partEmits:List<yimParticleEmitter> = New List<yimParticleEmitter>()
	
	Field delayedDelList:List<yimSprite> = New List<yimSprite>()
	Field delayedDelNum:Int = 10
	
	Field camPos:yimVec2D = New yimVec2D(0.0, 0.0)
	Field camAng:Float = 0.0
	
	Field zoomLevel:Float = 1.0
	Field maxZoom:Float = 5.0
	Field minZoom:Float = 0.1
	
	Field mapMouse:yimVec2D = New yimVec2D(0, 0)
	
	Method New(_eng:yimEngine, vs:yimVec2D)
		vScale.Copy(vs)
		SetCurLayer(AddLayer("Default"))
		eng = _eng
	End
	
	Method Reset()
		For Local l:=EachIn layerList
			l.Reset()
		Next
		
		vScale.Copy(eng.origScale)
		delayedDelList.Clear()
		partEmits.Clear()
		camPos.Set(0, 0)
		camAng = 0.0
		ResetCameraZoom()
	End
	
	Method ZoomCamera(z:Float)
		zoomLevel += z
		If zoomLevel < minZoom
			zoomLevel = minZoom
		EndIf
		
		If zoomLevel > maxZoom
			zoomLevel = maxZoom
		EndIf
		
		vScale.Set(eng.origScale.x*zoomLevel, eng.origScale.y*zoomLevel)
	End
	
	Method ResetCameraZoom()
		zoomLevel = 1.0
		ZoomCamera(0.0)
	End
	
	Method AddLayer:yimSpriteLayer(_name:String)
		If Not GetLayerByName(_name)
			Local tLayer:yimSpriteLayer = New yimSpriteLayer(Self, _name)
			layerList.AddLast(tLayer)
			Return tLayer
		Else
			LogMe("Error: Layer by that name ( "+_name+" ) already exists")
			Return Null
		Endif
	End
	
	Method AddSprite(spr:yimSprite)
		curLayer.AddSprite(spr)
		spr.SetVirts(vScale)
		spr.drawRect = New yimRect(0, 0, spr.img.Width(), spr.img.Height())
		spr.camPos = camPos
	End
	
	Method RemoveSprite(spr:yimSprite)
		curLayer.RemoveSprite(spr)
	End
	
	Method SetCurLayer(layer:yimSpriteLayer)
		curLayer = layer
	End
	
	Method GetLayerByName:yimSpriteLayer(name:String)
		For Local tLayer:= Eachin layerList
			If tLayer.name = name
				Return tLayer
			Endif
		Next
		Return Null
	End
	
	Method Update()
		Local time:Int = Millisecs()
		mapMouse.Set(eng.ScreenToMapX(MouseX(), MouseY()), eng.ScreenToMapY(MouseX(), MouseY()))
		
		If b2dWorld
			b2dWorld.Update()
		EndIf
		
		For Local pe:yimParticleEmitter = EachIn partEmits
			pe.Update(0, 0, time, 0.2)
			If pe.deathTime > -1 And time > pe.deathTime
				partEmits.Remove(pe)
			EndIf
		Next
		
		
		If delayedDelList.Count() > 0

			Local count:= 0
			Local tSpr:yimSprite
			
			While count < delayedDelNum
				tSpr = delayedDelList.RemoveFirst()
				If Not tSpr
					Exit
				EndIf
				tSpr.delayedDel = False
				RemoveSprite(tSpr)
				count += 1
				If delayedDelList.Count() = 0
					Exit
				EndIf
			Wend
					
		EndIf
		
		For Local tLayer:= Eachin layerList
			If tLayer.visible
				tLayer.Update()
			Endif
		Next
	End
	
	Method Render()
		Rotate(camAng)
		Scale(vScale.x, vScale.y)
		Translate(-camPos.x, camPos.y)
		
		For Local tLayer:= Eachin layerList
			If tLayer.visible
				tLayer.Render()
			Endif
		Next
		
		If b2dWorld
			b2dWorld.Render()
		EndIf
	End
End
